﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using WSManager.Model;
using StringVariables;

namespace WSManager.DataAccess
{
    public static class ModelXmlSerializer
    {
        public static XElement ToXml(WebImage item)
        {

            return new XElement("image",
                    new XAttribute("path", item.Path),
                    new XAttribute("id", item.Id),
                    from i in new[] { item.ImageData } where i != null select new XAttribute("data", Convert.ToBase64String(i)));
        }
        public static XElement ToXml(WebFile item)
        {
            return new XElement("file",
                   new XAttribute("path", item.Path),
                   new XAttribute("size", item.Size),
                   new XAttribute("name", item.Name),
                   from i in new[] { item.Data } where i != null select new XAttribute("data", Convert.ToBase64String(i))
                );
        }
        public static XElement ToXml(Category item)
        {
            return new XElement("category",
                new XAttribute("name", item.Name),
                new XAttribute("id", item.Id),
                new XElement("description", item.Description),
                from category in item.Subcategories
                select ModelXmlSerializer.ToXml(category)
                    );
        }
        public static XElement ToXml(Article item)
        {
            if (item == null) throw new ArgumentNullException("item");
            return new XElement("article",
                new XElement("name", item.Name),
                new XElement("description", item.Description),
                item.Content,
                item.Categories.Select(c => new XElement("category", c.Id)),
                (item.Metadata ?? new Dictionary<string, string>()).Select(m => new XElement(m.Value, new XAttribute("name", m.Key))));
        }
        public static XElement ToXml(Web item)
        {
            return new XElement("web",
                    item.Articles.Select(ToXml),
                    item.Categories.Select(ToXml),
                    item.Images.Select(ToXml),
                    item.Files.Select(ToXml),
                    ToXml(item.Metadata));
        }
        public static XElement ToXml(VariableDefinition item)
        {
            if (item == null) throw new ArgumentNullException("item");
            return new XElement("variableDefinition",
                new XAttribute("name", item.Name),
                new XAttribute("defaultValue", item.DefaultValue),
                new XAttribute("allowNull", item.AllowNull),
                new XAttribute("type", item.Type.FullName));
        }
        public static XElement ToXml(WebMetadata item)
        {
            return new XElement("metadata",
                new XElement("articleMetadataDefinition", from i in item.ArticleMetadataDefinition
                                                          select ModelXmlSerializer.ToXml(i)));
        }


        public static Article ToArticle(XElement xml, IEnumerable<Category> allCategories)
        {
            Article item = new Article();
            item.Name = xml.Element("name").Value;
            if (xml.Element("description") != null)
                item.Description = xml.Element("description").Value;
            else item.Description = "";
            item.Categories = new List<Category>(
                from e in xml.Elements("category")
                let cat = allCategories.FindCategory(e.Value)
                where cat != null
                select cat);
            item.Content = xml.Element("content") ?? new XElement("content");
            item.Metadata = new Dictionary<string, string>();
            foreach (var meta in xml.Elements("meta"))
            {
                item.Metadata.Add(meta.Attribute("name").Value, meta.Value);
            }
            return item;
        }
        public static Category ToCategory(XElement xml)
        {
            var item = new Category();
            item.Name = xml.Attribute("name").Value;
            item.Id = xml.Attribute("id").Value;
            if (xml.Element("description") != null)
                item.Description = xml.Element("description").Value;
            else item.Description = "";
            item.Subcategories = new List<Category>(from c in xml.Elements("category")
                                                    select ModelXmlSerializer.ToCategory(c));
            return item;
        }
        public static WebImage ToWebImage(XElement xml)
        {
            var item = new WebImage();
            item.Id = (string)xml.Attribute("id");
            item.Path = (string)xml.Attribute("path");
            if (xml.Attribute("data") != null)
            {
                item.ImageData = Convert.FromBase64String(xml.Attribute("data").Value);
            }
            return item;
        }
        public static WebFile ToWebFile(XElement xml)
        {
            WebFile item = new WebFile();
            item.Path = (string)xml.Attribute("path");
            item.Name = (string)xml.Attribute("name") ?? new string(item.Path.Reverse().TakeWhile(c => c != '/' || c != '\\').Reverse().ToArray());
            item.Size = (int)xml.Attribute("size");
            if (xml.Element("data") != null)
            {
// ReSharper disable once PossibleNullReferenceException
                item.Data = Convert.FromBase64String(xml.Element("data").Value);
            }
            return item;
        }
        public static Web ToWeb(XElement xml)
        {
            Web item = new Web();
            item.Categories = xml.Elements("category").Select(ToCategory);
            item.Articles = xml.Elements("article").Select(el => ToArticle(el, item.Categories));
            item.Images = xml.Elements("images").Select(ToWebImage);
            item.Files = xml.Elements("files").Select(ToWebFile);
            if (xml.Element("metadata") != null)
                item.Metadata = ModelXmlSerializer.ToWebMetadata(xml.Element("metadata"));
            return item;
        }
        public static VariableDefinition ToVariableDefinition(XElement xml)
        {
            return new VariableDefinition()
            {
                Name = (string)xml.Attribute("name"),
                DefaultValue = (string)xml.Attribute("defaultValue"),
                AllowNull = (bool)xml.Attribute("allowNull"),
                Type = VariableType.Parse((string)xml.Attribute("type"))
            };
        }
        public static WebMetadata ToWebMetadata(XElement xml)
        {
            return new WebMetadata()
            {
                ArticleMetadataDefinition = xml.Element("articleMetadataDefinition").Elements("variableDefinition").Select(s => ModelXmlSerializer.ToVariableDefinition(s)).ToList()
            };
        }
    }

}
